package com.gitee.wsl.data.savable

import kotlin.reflect.KType
import kotlin.reflect.typeOf

class SavableHandler(
    private val stateSaver: Savable
) {

    private class Saver<T>(
        val kType: KType,
        val saveValue: () -> T
    )

    private val savers = mutableMapOf<String, Saver<*>>()

    fun <T> getSaved(key: String, kType: KType): T? {
        return stateSaver.restoreState(key, kType)
    }

    fun <T> setSaved(key: String, kType: KType, value: T?) {
        return stateSaver.saveState(key, kType, value)
    }

    fun <T> setSaver(key: String, kType: KType, saveValue: () -> T) {
        if (savers.contains(key)) {
            throw IllegalArgumentException("Saver with for key [$key] already exists")
        }

        savers[key] = Saver(kType, saveValue)
    }

    fun removeSaver(key: String) {
        savers.remove(key)
    }

    fun saveState() {
        savers.mapValues { entry ->
            stateSaver.saveState(entry.key, entry.value.kType, entry.value.saveValue())
        }
    }

    internal fun release() {
        savers.clear()
    }
}

inline fun <reified T> SavableHandler.getSaved(key: String): T? {
    return getSaved(key, typeOf<T>())
}

inline fun <reified T> SavableHandler.setSaved(key: String, value: T?) {
    return setSaved(key, typeOf<T>(), value)
}

inline fun <reified T> SavableHandler.setSaver(key: String, noinline saveValue: () -> T) {
    setSaver(key, typeOf<T>(), saveValue)
}